import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';


import 'kq_rainbow_tips_builder.dart';
import 'kq_rainbow_value.dart';

/// 彩虹条
/// 要实现点击组件外区域关闭，就必须在最外层包一个GestureDetector，并用globeKey在onTap中实现close方法
class KqRainbowBar extends StatefulWidget {
  const KqRainbowBar({
    Key? key,
    required this.context,
    this.height,
    this.width,
    this.data,
    this.rainbowBarClickListener,
    this.rainbowBarMoveListener,
    this.tipsBuilder,
    this.customTipsPainter,
  }) : super(key: key);

  /// 当前页面的上下文
  final BuildContext context;

  /// 高度，如果外部容器有高度，可以不传
  final double? height;

  /// 宽度，如果外部容器有宽度，可以不传
  final double? width;

  final List<KqRainbowValue>? data;

  /// 彩虹条的按下回调
  final OnKqRainbowBarClickListener? rainbowBarClickListener;

  /// 彩虹条的移动回调
  final OnKqRainbowBarMoveListener? rainbowBarMoveListener;

  /// tips的构造器
  final KqRbTipsBuilder? tipsBuilder;

  /// 如果构造器无法实现，则传入自定义的CustomPainter来绘制tips
  final CustomPainter? customTipsPainter;

  @override
  State<StatefulWidget> createState() {
    return KqRainbowBarState();
  }
}

class KqRainbowBarState extends State<KqRainbowBar> {
  /// 要存的每项开头坐标
  List<double> startPositions = [];

  /// 要存的每项中间坐标
  List<double> centerPositions = [];

  /// 要存的每项结束坐标
  List<double> endPositions = [];

  /// 点击item的中心坐标(组件内)
  double? centerPosition;

  /// 组件内坐标与全局坐标的水平距离
  double? globalLocalDx;

  /// 是否显示
  bool isShow = false;

  /// 文案
  String text = "";

  /// 主动关闭tips,用globeKey调用。
  void closeTips() {
    setState(() {
      isShow = false;
    });
  }

  void checkPositionForPanDown(DragDownDetails details) {
    //获取当前触摸点的局部坐标
    Offset localPosition = details.localPosition;
    //获取当前触摸点的全局坐标
    Offset globalPosition = details.globalPosition;
    for (int i = 0; i < centerPositions.length; i++) {
      if (localPosition.dx < endPositions.elementAt(i) &&
          localPosition.dx > startPositions.elementAt(i)) {
        globalLocalDx = globalPosition.dx - localPosition.dx;
        setState(() {
          isShow = true;
          centerPosition = centerPositions.elementAt(i);
          text = widget.data!.elementAt(i).text;
        });
        if (widget.rainbowBarClickListener != null) {
          widget.rainbowBarClickListener!(
              i,
              Offset(centerPosition!, 0),
              Offset(centerPosition! + globalLocalDx!,
                  globalPosition.dy - localPosition.dy),
              widget.data!.elementAt(i));
        }
      }
    }
  }

  void checkPositionForMove(DragUpdateDetails details) {
    //获取当前触摸点的局部坐标
    Offset localPosition = details.localPosition;
    //获取当前触摸点的全局坐标
    Offset globalPosition = details.globalPosition;
    for (int i = 0; i < centerPositions.length; i++) {
      if (localPosition.dx < endPositions.elementAt(i) &&
          localPosition.dx > startPositions.elementAt(i)) {
        globalLocalDx = globalPosition.dx - localPosition.dx;
        setState(() {
          isShow = true;
          centerPosition = centerPositions.elementAt(i);
          text = widget.data!.elementAt(i).text;
        });
        if (widget.rainbowBarMoveListener != null) {
          widget.rainbowBarMoveListener!(
              i,
              Offset(centerPosition!, 0),
              Offset(centerPosition! + globalLocalDx!,
                  globalPosition.dy - localPosition.dy),
              widget.data!.elementAt(i));
        }
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanDown: (details) {
        checkPositionForPanDown(details);
      },
      onPanUpdate: (dragUpdateDetails) {
        checkPositionForMove(dragUpdateDetails);
      },
      onTap: () {
        /// 这里写一个空的onTap的目的是，与外层的onTap竞争，并胜出，来达到在该组件上点击时，不触发外层onTap的目的
      },
      child: RepaintBoundary(
        child: CustomPaint(
          foregroundPainter: widget.customTipsPainter ??
              TipsPainter(
                context: widget.context,
                isShow: isShow,
                centerPosition: centerPosition,
                globalLocalDx: globalLocalDx,
                tipsBuilder: widget.tipsBuilder ?? KqRbTipsBuilder(),
                text: text,
              ),
          painter: ItemPainter(
            itemHeight: widget.height,
            data: widget.data,
            rainbowBarEndDrawListener:
                (startPositions, centerPositions, endPositions) {
              this.startPositions = startPositions;
              this.centerPositions = centerPositions;
              this.endPositions = endPositions;
            },
          ),
          size:
              widget.width == null ? Size.zero : Size.fromWidth(widget.width!),
        ),
      ),
    );
  }
}

/// 彩虹条的点击返回
typedef OnKqRainbowBarClickListener = void Function(
    int position,

    /// 选中item的中间位置的控件内坐标
    Offset dialogShowPositionLocal,

    /// 选中item的中间位置的屏幕内坐标
    Offset dialogShowPositionGlobal,
    KqRainbowValue value);

/// 彩虹条的移动返回
typedef OnKqRainbowBarMoveListener = void Function(
    int position,

    /// 选中item的中间位置的控件内坐标
    Offset dialogShowPositionLocal,

    /// 选中item的中间位置的屏幕内坐标
    Offset dialogShowPositionGlobal,
    KqRainbowValue value);

/// 彩虹条的绘制结束返回绘制坐标
typedef OnKqRainbowBarEndDrawListener = void Function(
    List<double> startPositions,
    List<double> centerPositions,
    List<double> endPositions);

class ItemPainter extends CustomPainter {
  ItemPainter(
      {Key? key, this.itemHeight, this.data, this.rainbowBarEndDrawListener});

  final Paint _paint = Paint()..style = PaintingStyle.fill;

  /// 统一设置彩虹条高度，不是总高度
  final double? itemHeight;

  final List<KqRainbowValue>? data;

  final OnKqRainbowBarEndDrawListener? rainbowBarEndDrawListener;

  List<double> startPositions = [];
  List<double> centerPositions = [];
  List<double> endPositions = [];

  @override
  void paint(Canvas canvas, Size size) {
    startPositions = [];
    centerPositions = [];
    endPositions = [];
    if (data == null) {
      return;
    }
    double totalWidth = 0;
    for (KqRainbowValue item in data!) {
      totalWidth = totalWidth + item.value;
    }
    double simpleWidth = size.width / totalWidth;
    double countWidth = 0;
    for (int i = 0; i < data!.length; i++) {
      KqRainbowValue value = data!.elementAt(i);
      _paint.color = value.color;

      /// 获取左上角和右下角的坐标
      Offset startLeftTop = Offset(countWidth, 0);
      Offset endRightBottom = Offset(
          countWidth + simpleWidth * value.value, itemHeight ?? size.height);
      canvas.drawRect(Rect.fromPoints(startLeftTop, endRightBottom), _paint);
      final double oldWidth = countWidth;
      startPositions.add(oldWidth);
      countWidth = countWidth + simpleWidth * value.value;
      centerPositions.add(countWidth - (countWidth - oldWidth) / 2);
      endPositions.add(countWidth);
    }
    if (rainbowBarEndDrawListener != null) {
      rainbowBarEndDrawListener!(startPositions, centerPositions, endPositions);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}

class TipsPainter extends CustomPainter {
  TipsPainter(
      {Key? key,
      required this.context,
      this.isShow = true,
      this.centerPosition,
      this.globalLocalDx,
      this.text = "",
      required this.tipsBuilder});

  BuildContext context;

  /// 是否显示
  bool isShow;

  double? centerPosition;

  double? globalLocalDx;

  KqRbTipsBuilder tipsBuilder;

  String? text;

  @override
  void paint(Canvas canvas, Size size) {
    if (isShow && centerPosition != null) {
      drawArrow(canvas, size);
      drawWindow(canvas, size);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

  /// 绘制箭头
  void drawArrow(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..style = PaintingStyle.fill
      ..color = tipsBuilder.backgroundColor!;
    Path path = Path();
    path.moveTo(centerPosition!, -tipsBuilder.tipsOffset!);
    path.lineTo(centerPosition! - tipsBuilder.arrowWidth! / 2,
        -tipsBuilder.arrowHeight! - tipsBuilder.tipsOffset!);
    path.lineTo(centerPosition! + tipsBuilder.arrowWidth! / 2,
        -tipsBuilder.arrowHeight! - tipsBuilder.tipsOffset!);
    path.close();
    canvas.drawPath(path, paint);
  }

  /// 绘制窗口
  void drawWindow(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..style = PaintingStyle.fill
      ..color = tipsBuilder.backgroundColor!;

    /// 生成绘制文本，但是先不绘制到画布上
    TextPainter textPainter = TextPainter(
      text: TextSpan(
        text: text,
        style: tipsBuilder.textStyle,
      ),
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );
    textPainter.layout();

    /// 计算tips中心点和宽度
    /// 判断绘制结果会不会在左右两侧超出屏幕
    /// 这里的移动距离特地加了1像素是为了美观
    double width = textPainter.width +
        tipsBuilder.windowPadding!.left +
        tipsBuilder.windowPadding!.right;
    double leftOverSize = centerPosition! - width / 2 + globalLocalDx!;
    double rightOverSize = MediaQuery.of(context).size.width -
        (centerPosition! + width / 2 + globalLocalDx!);
    leftOverSize = leftOverSize < 0 ? -leftOverSize - 1 : 0;
    rightOverSize = rightOverSize < 0 ? -rightOverSize - 1 : 0;
    Offset center = Offset(
        centerPosition! + leftOverSize - rightOverSize,
        -tipsBuilder.tipsOffset! -
            tipsBuilder.arrowHeight! -
            tipsBuilder.windowPadding!.bottom -
            textPainter.height / 2);
    Rect rect = Rect.fromCenter(
        center: center,
        width: textPainter.width +
            tipsBuilder.windowPadding!.left +
            tipsBuilder.windowPadding!.right,
        height: textPainter.height +
            tipsBuilder.windowPadding!.top +
            tipsBuilder.windowPadding!.bottom);
    canvas.drawRRect(RRect.fromRectAndRadius(rect, tipsBuilder.radius!), paint);
    textPainter.paint(
        canvas,
        Offset(center.dx - textPainter.width / 2,
            center.dy - textPainter.height / 2));
  }
}
